package dryven.codegen.asm;

import java.util.LinkedList;
import java.util.List;

import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import dryven.codegen.asm.typeinfo.ClassTypeInfo;

public class TryCatchBlock {
	
	private MethodBuilder _builder;
	private Label _startLabel;
	private Label _endLabel;
	private Label _jumpOverHandlersLabel;
	private List<ExceptionHandler> _handlers;
	private boolean _isStarted = false;
	
	public TryCatchBlock(MethodBuilder builder) {
		super();
		_builder = builder;
		
		_startLabel = new Label();
		_endLabel = new Label();
		_jumpOverHandlersLabel = new Label();
		_handlers = new LinkedList<ExceptionHandler>();
	}
	public void start(Scope scope) {
		start();
		scope.setBuilder(_builder);
		scope.addCode();
		finish();
	}
	
	public void start() {
		MethodVisitor mv = _builder.getMethodVisitor();
		for (ExceptionHandler handler : _handlers) {
			mv.visitTryCatchBlock(_startLabel, _endLabel, handler.getHandlerLabel(), new ClassTypeInfo(handler.getExceptionType()).getInternalClassName());
		}
		mv.visitLabel(_startLabel);
		_isStarted = true;
	}
	
	public void finish() {
		MethodVisitor mv = _builder.getMethodVisitor();
		mv.visitLabel(_endLabel);
		mv.visitJumpInsn(Opcodes.GOTO, _jumpOverHandlersLabel);
	}
	
	public ExceptionHandler addExceptionHandler(Class<? extends Throwable> exceptionClass) {
		if(_isStarted) {
			throw new RuntimeException("Try-catch block already started, can't add any handlers anymore. Call addExceptionHandler before start or create a nested try-catch block.");
		}
		ExceptionHandler handler = new ExceptionHandler(exceptionClass, this);
		_handlers.add(handler);
		return handler;
	}
	
	public MethodBuilder getBuilder() {
		return _builder;
	}
	
	protected boolean isOnlyUnfinishedExceptionHandler(ExceptionHandler e) {
		if(e.isFinished()) {
			throw new RuntimeException("handler already finished");
		}
		for (ExceptionHandler h : _handlers) {
			if(h!=e && !h.isFinished()) {
				return false;
			}
		}
		return true;
	}
	protected Label getJumpOverHandlersLabel() {
		return _jumpOverHandlersLabel;
	}
}
